//
//  JKQRCodeViewController.swift
//  JKWeibo
//
//  Created by albert on 16/5/13.
//  Copyright © 2016年 albert. All rights reserved.
//  二维码 扫一扫控制器

import UIKit
import AVFoundation

class JKQRCodeViewController: UIViewController {
    
    /** 容器视图 */
    @IBOutlet weak var containerView: UIView!
    /** 扫描结果label */
    @IBOutlet weak var scanResultLabel: UILabel!
    /** 底部的工具条 */
    @IBOutlet weak var customTabBar: UITabBar!
    /** 冲击波视图 */
    @IBOutlet weak var scanLineImageView: UIImageView!
    /** 冲击波顶部约束 */
    @IBOutlet weak var scanLineTopConstraint: NSLayoutConstraint!
    /** 容器视图高度约束，可用来设置扫描动画 */
    @IBOutlet weak var containerViewHeightConstraint: NSLayoutConstraint!
    
    /** 专门保存描边图层的父图层 */
    private lazy var containerLayer: CALayer = CALayer()
    
    /** 捕捉会话 */
    private lazy var session: AVCaptureSession = AVCaptureSession()
    /** 预览图层 这里必须加上self */
    private lazy var preLayer: AVCaptureVideoPreviewLayer = AVCaptureVideoPreviewLayer(session: self.session);
    
    /** 输出对象 */
    private lazy var outPut: AVCaptureMetadataOutput = {
        let out = AVCaptureMetadataOutput()
        
        // 设置输出对象解析数据时感兴趣的区域
        // 默认值是 CGRect(x: 0, y: 0, width: 1, height: 1)
        // 通过这个值的观察，我们发现传入的是比例
        // 苹果坑爹的将这个比例设置为横屏的，即home健在右侧的横屏
        let x = self.containerView.y / JKScreenH
        let y = self.containerView.x / JKScreenW
        let width = self.containerView.height / JKScreenH
        let height = self.containerView.width / JKScreenW
        out.rectOfInterest = CGRect(x: x, y: y, width: width, height: height)
        
        return out
    }()
    
    /** 输入对象 */
    private lazy var input: AVCaptureDeviceInput? = {
        let device = AVCaptureDevice.defaultDeviceWithMediaType(AVMediaTypeVideo)
        
        return try? AVCaptureDeviceInput(device: device)
    }()
    
    //MARK: - 开始扫描
    private func startScan(){
        // 1.判断输入对象能否添加到会话中
        if !session.canAddInput(input){
            return
        }
        
        // 2.判断输出对象能否添加到会话中
        if !session.canAddOutput(outPut){
            return
        }
        
        // 3.添加输入输出设备到会话中
        session.addInput(input)
        session.addOutput(outPut)
        
        // 4.设置输出对象能够解析的数据类型，这里省事一点，设置为所有可用的types
        outPut.metadataObjectTypes = outPut.availableMetadataObjectTypes
        
        // 5.设置输出代理解析输出解析到的数据
        outPut.setMetadataObjectsDelegate(self, queue: dispatch_get_main_queue())
        
        // 6.添加到预览图层
        view.layer.insertSublayer(preLayer, atIndex: 0)
        preLayer.frame = view.bounds
        
        // 7.添加容器图层
        view.layer.addSublayer(containerLayer)
        containerLayer.frame = view.layer.bounds
        
        // 8.开始扫描
        session.startRunning()
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        
        // 1.默认选中二维码
        customTabBar.selectedItem = customTabBar.items!.first
        
        // 2.设置tabBar的代理，监听底部tabBar工具条的点击
        customTabBar.delegate = self
        
        // 3.一开始让冲击波在顶部
        scanLineTopConstraint.constant = -containerViewHeightConstraint.constant
        self.view.layoutIfNeeded()
        
        // 4.开始扫描
        startScan()
    }
    
    override func viewDidAppear(animated: Bool) {
        super.viewDidAppear(animated)
        // 开始扫描动画
        startAnimation()
    }
    
    //MARK: - 开始扫描动画
    private func startAnimation(){
        scanLineTopConstraint.constant = -containerViewHeightConstraint.constant
        self.view.layoutIfNeeded()
        
        UIView.animateWithDuration(1.5) { () -> Void in
            UIView.setAnimationRepeatCount(MAXFLOAT)
            self.scanLineTopConstraint.constant = self.containerViewHeightConstraint.constant
            self.view.layoutIfNeeded()
        }
    }
    
    // MARK: - 点击左上角关闭
    @IBAction func closeBtnClick(sender: AnyObject) {
        dismissViewControllerAnimated(true, completion: nil)
    }
    
    // MARK: - 点击右上角相册
    @IBAction func albumBtnClick(sender: AnyObject) {
        
        // 1.先判断能否打开相册
        if !UIImagePickerController.isSourceTypeAvailable(UIImagePickerControllerSourceType.PhotoLibrary){
            return
        }
        
        // 2.创建照片选选择控制器
        let imagePickerVc = UIImagePickerController()
        
        // 3.设置照片源
        imagePickerVc.sourceType = UIImagePickerControllerSourceType.PhotoLibrary
        
        // 4.设置代理
        imagePickerVc.delegate = self
        
        // 5.弹出照片选择控制器
        presentViewController(imagePickerVc, animated: true, completion: nil)
    }
}

// MARK: - ===照片选中控制器的代理===
extension JKQRCodeViewController: UIImagePickerControllerDelegate, UINavigationControllerDelegate{
    func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]){
        
        // 1.取出选中的照片
        guard let image = info[UIImagePickerControllerOriginalImage] as? UIImage else {
            return
        }
        
        guard let ciImae = CIImage(image: image) else {
            return
        }
        
        // 2.从选中的照片中读取二维码
        // 2.1创建一个探测器   CIDetectorTypeFace可以人脸识别
        // CIDetectorAccuracy: 精准度  CIDetectorAccuracyHigh就是精准度高，但是可能较慢
        // 精度调成high还是没用啊，有些还是扫不出来，但是别的app能扫出来！！！
        let detector = CIDetector(ofType: CIDetectorTypeQRCode, context: nil, options: [CIDetectorAccuracy: CIDetectorAccuracyHigh])
        // 2.2利用探测器探测数据
        let results = detector.featuresInImage(ciImae)
        // 2.3取出探测到的数据
        for result in results{
            //JKLog((result as! CIQRCodeFeature).messageString)
            scanResultLabel.text = (result as! CIQRCodeFeature).messageString
        }
        
        // 3.退出照片选中控制器
        picker.dismissViewControllerAnimated(true, completion: nil)
    }
}

// MARK: - ===二维码输出代理===
extension JKQRCodeViewController: AVCaptureMetadataOutputObjectsDelegate{
    // 只要扫描到结果就会调用
    func captureOutput(captureOutput: AVCaptureOutput!, didOutputMetadataObjects metadataObjects: [AnyObject]!, fromConnection connection: AVCaptureConnection!){
        
        // 1.显示结果
        scanResultLabel.text = metadataObjects.last?.stringValue
        
        // 先移除之前的描边图层
        removeShapeLayers()
        
        // 2.拿到扫描的结果
        guard let metaData = metadataObjects.last as? AVMetadataObject else {
            return
        }
        
        // bounds就是将二维码包起来的正矩形，corners就是二维码的四个角的点，我们使用corners
        // 转换前 bounds={ 0.6,0.0 0.2x0.3 }>corners { 0.6,0.3 0.8,0.3 0.8,0.1 0.6,0.0 }
        // 转换后 bounds={ 61.5,256.9 50.3x49.5 }>corners { 64.5,256.9 61.5,303.2 107.9,306.4 111.8,261.0 }
        guard let objc = preLayer.transformedMetadataObjectForMetadataObject(metaData) as? AVMetadataMachineReadableCodeObject else {
            return
        }
        
        // 3.对扫描到的二维码进行描边
        drawLines(objc)
    }
    
    //MARK: - 绘制描边
    private func drawLines(metaData: AVMetadataMachineReadableCodeObject){
        
        // 0.安全校验，看metaData的corners是否有值
        // corners数组中存放的是字典，每个字典有两个key X和Y，一个字典就是一个二维码的一个角的点
        guard let pointsArray = metaData.corners else {
            return
        }
        
        // 1.创建图层，用于保存绘制的矩形
        let shapeLayer = CAShapeLayer()
        shapeLayer.lineWidth = 2
        shapeLayer.strokeColor = UIColor.redColor().CGColor
        // 填充颜色默认是黑色，改成透明
        shapeLayer.fillColor = UIColor.clearColor().CGColor
        
        // 2.创建路UIBezierPath径，绘制矩形
        let path = UIBezierPath()
        var point = CGPointZero
        let count = metaData.corners.count

        // 2.1获取二维码的点
        for i in 0..<count{
            // 根据字典获取一个CGPoint
            // UnsafeMutablePointer<CGPoint>就代表OC中传地址 &point
            CGPointMakeWithDictionaryRepresentation((pointsArray[i] as! CFDictionaryRef), &point)
            if i == 0{
                // 起点
                path.moveToPoint(point)
                
            }else{
                // 连线
                path.addLineToPoint(point)
            }
        }
        // 2.2关闭路径
        path.closePath()
        
        // 这里不能stroke，不然报一大堆错啊
        //path.stroke()
        
        // 3.设置图层的路径
        shapeLayer.path = path.CGPath
        
        // 4.将绘制的图层添加上去
        // 这里最好不要添加到view的图层上，因为view的layer不能随便移除
        //view.layer.addSublayer(shapeLayer)
        
        // 将绘制的图层保存在专门管理它的图层上
        containerLayer.addSublayer(shapeLayer)
    }
    
    //MARK: - 移除描边图层
    private func removeShapeLayers(){
        // 判断是否有描边图层
        guard let subLayers = containerLayer.sublayers else {
            return
        }
        
        // 移除描边图层
        for layer in subLayers {
            layer.removeFromSuperlayer()
        }
    }
}

// MARK: - ===tabBar代理===
extension JKQRCodeViewController: UITabBarDelegate{
    func tabBar(tabBar: UITabBar, didSelectItem item: UITabBarItem){
        
        // 是否是第一个item 二维码
        let isFirstItem = (item == tabBar.items!.first)
        
        // 根据当前选中的按钮重新设置二维码容器视图的高度
        containerViewHeightConstraint.constant = isFirstItem ? 228 : 114
        view.layoutIfNeeded()
        
        // 移除动画
        scanLineImageView.layer.removeAllAnimations()
        
        // 重新开始动画
        startAnimation()
    }
}
